package com.aldobucchi.graph.query.adapters
{
	
	import flash.events.Event;
	import flash.utils.Dictionary;
	
	import mx.events.PropertyChangeEvent;
	
	import com.aldobucchi.graph.query.Query;
	import com.aldobucchi.graph.query.QueryEvent;
	import com.aldobucchi.utils.priority.AbstractPrioritizable;





	// TODO: rename to... FlatObjectAdapter
	public class FlatAdapter extends AbstractPrioritizable // implements IPropertyChangeNotifier
	{
		

		private var _node:*;
		public function get node( ):*
		{
			return _node;
		}
		
		
		private var _hasPendingQueries:Boolean = false;
		[Bindable("hasPendingQueriesChanged")]
		public function get hasPendingQueries( ):Boolean
		{
			return _hasPendingQueries;
		}
		private function setHasPendingQueries( v:Boolean ):void
		{
			if ( v == _hasPendingQueries )
				return;
			_hasPendingQueries = v;
			dispatchEvent( new Event( "hasPendingQueriesChanged" ) );		
		}
		
		
		
		private var _empty:Boolean=true;
		[Bindable("emptyChanged")]
		public function get empty( ):Boolean
		{
			return _empty;
		}
		

		
		
		
		
		
		
		private var propSpecs:Object = { };
		
		
		private var query2spec:Dictionary = new Dictionary( );
		

		private var propValues:Object = { };






		override public function set priority( v:uint ):void
		{
			
			if ( super.priority == v )
				return;
			
			super.priority = v;
			
			// reset internal query priorities
			
			for ( var q:* in query2spec )
				( q as Query ).priority = this.priority;
		
		}

		
		
		
		
		
		public function FlatAdapter( node:*, priority:uint = 5 )
		{
			_node = node;
			this.priority = priority;
		}
		
		
		
		

		private function updateHasPendingQueries( ):void
		{
			for ( var q:* in query2spec )
			{
				setHasPendingQueries( true );
				return;				
			}
			setHasPendingQueries( false );
		}
		
		
		
		protected function getPropValue( propName:* ):*
		{
			return propValues[ propName ];
		}
		
		
		protected function translateValue( value:* ):*
		{
			return value;
		}
		
		
		protected function addPropSpec( propSpec:PropertySpec ):void
		{
			propSpecs[ propSpec.name ] = propSpec;		
		}
		
		
		
		public function refresh( ):void
		{


			if ( _empty )
			{
				_empty=false;
				dispatchEvent( new Event( "emptyChanged" ) );
			
			}


			for each ( var propSpec:PropertySpec in propSpecs )
			{
				var q:Query = propSpec.buildQuery( node );
				q.priority = priority;
				q.addEventListener( QueryEvent.RESULT	, query_result );
				q.addEventListener( QueryEvent.ERROR	, query_error );
				query2spec[ q ] = propSpec;
				q.execute( );
			}
			
			updateHasPendingQueries( );
		
		}
				
		
				
		
		private function query_result( event:QueryEvent ):void
		{
		
			var query		:Query 			= event.target as Query;
			var propSpec	:PropertySpec 	= query2spec[ query ] as PropertySpec;
			var name		:String			= propSpec.name;
			
			// TODO: for now we assume limit==1
			
			
			
			var result:*;
			try{
				result = translateValue( query.result[ 0 ] );
			}catch( e:Error){}
			
			
			if ( propValues[ name ] != result )
			{
				var oldValue:* = propValues[ name ];			
			
				propValues[ name ] = result;
			
				dispatchEvent( new Event( name + "Changed" ) );
				dispatchEvent( PropertyChangeEvent.createUpdateEvent( this, name, oldValue, result ) );
				
			}
			
			delete query2spec[ query ];
			
			updateHasPendingQueries( ); // in case this was the last one
		
		}
		
		
		private function query_error( event:QueryEvent ):void
		{
		
			
		
		
		}
		
		
	}
	
}
